﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Fluq
{
	public sealed class DependencyLifetime : IDependencyLifetime
	{
		private IList<DependencyObject> _objects = new List<DependencyObject>();
		
		public bool TryAcquire(object graphId, IDependencyContainer container, IDependency dependency, out object instance)
		{
			DependencyObjectLifetime lifetime = new DependencyObjectLifetime(container);

			container = new DependencyContainer(container.Registry, container.Resolver, container.Composer, lifetime);

			bool track = false;

			Func<object> factory = () =>
			{
				track = true;

				return dependency.Factory(container, dependency.Parameters);
			};

			instance = dependency.Lifestyle.Acquire(graphId, dependency.Key, factory);

			if (instance != null)
			{
				if (track)
				{
					_objects.Add(new DependencyObject(instance, dependency, lifetime.Children));
				}

				return true;
			}
			else
			{
				return false;
			}
		}

		public bool TryDiscard(IDependencyContainer container, object instance)
		{
			DependencyObject o = _objects.Where(i => i.Instance == instance).FirstOrDefault();

			if (o != null)
			{
				Discard(o, container, () => _objects.Remove(o));

				return true;
			}
			else
			{
				return false;
			}
		}

		private static void Discard(DependencyObject o, IDependencyContainer container, Action cleanUp)
		{
			IDependency dependency = o.Dependency;

			dependency.Lifestyle.Discard(dependency.Key, (value) =>
			{
				foreach (object child in o.Children)
				{
					container.Resolver.TryRelease(container, child);
				}

				container.Composer.TryDestroy(value);

				cleanUp();
			}, o.Instance);
		}

		public void DiscardAll(IDependencyContainer container)
		{
			foreach (DependencyObject o in new List<DependencyObject>(_objects))
			{
				TryDiscard(container, o.Instance);
			}
		}
	}
}
